﻿using System;
using System.Collections.Generic;
using System.Linq;
using DataAccess.DataModel;

namespace DataAccess.DataAccess
{
    public class DataAccessClass
    {
        public bool CrearUsuario(string nombreUsuario, string password, bool clientePrepago, decimal saldoInicial)
        {
            try
            {
                using (CarSharingEntities entities = new CarSharingEntities())
                {
                    User user = new User
                                    {
                                        UserName = nombreUsuario,
                                        UserPassword = password,
                                        Activo = true,
                                        Prepago = clientePrepago,
                                        SaldoPrepago = clientePrepago ? saldoInicial : 0                                        
                                    };
                    entities.Users.AddObject(user);
                    entities.SaveChanges();
                    return true;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Modifica el usuario
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="esPrepago"></param>
        /// <param name="agregarSaldo"></param>
        /// <returns></returns>
        public bool ModificarUsuario(int userId, bool esPrepago, decimal agregarSaldo)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var usuario = (from userData in carSharingEntities.Users
                                  where userData.UserId == userId
                                  select userData).ToList();
                    if (usuario.Count==1)
                    {
                        foreach (var user in usuario)
                        {
                            if (esPrepago)
                            {
                                user.Prepago = true;
                                user.SaldoPrepago = user.SaldoPrepago + agregarSaldo;
                            }
                            else
                            {
                                user.Prepago = false;
                                user.SaldoPrepago = 0;
                            }
                        }
                        carSharingEntities.SaveChanges();
                        return true;
                    }
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Obtener el precio por kilometro recorrido
        /// </summary>
        /// <returns></returns>
        public decimal ObtenerPrecioPorKilometraje()
        {
            try
            {
                using (CarSharingEntities carSharingEntities= new CarSharingEntities())
                {
                    var query = (from costo in carSharingEntities.Costos
                                 select costo.PrecioPorKilometraje).ToList();
                    return query.Count==1 ? query.FirstOrDefault() : 0;
                }
            }
            catch (Exception)
            {
                return 0;
            }
        }

        /// <summary>
        /// Verifica si puede iniciar el viaje
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public bool IniciarViaje(int userId)
        {
            try
            {
                using (CarSharingEntities carSharingEntities= new CarSharingEntities())
                {
                    var query = (from viajes in carSharingEntities.Trips
                                 where viajes.UserId == userId &&
                                       viajes.Estado != (int) TripStatus.Ended
                                     select viajes).ToList();
                    foreach (Trip oldTrips in query)
                    {
                        oldTrips.Estado = (byte) TripStatus.Ended;
                        carSharingEntities.SaveChanges();
                        DecrementarSaldoUsuario(userId, oldTrips.CostoViaje);
                    }
                    if (ObtenerSaldoClienteActivo(userId) > 0 || ClientePospagoActivo(userId))
                    {
                        Trip trip = new Trip { UserId = userId, Estado = (byte) TripStatus.Started, CostoViaje = 0, Kilometraje = 0 };
                        carSharingEntities.Trips.AddObject(trip);
                        carSharingEntities.SaveChanges();
                        return true;
                    }
                    return false;
                }
            }
            catch (Exception exception)
            {
                return false;
            }
        }

        public bool ClientePospagoActivo(int userId)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var usuario = (from userData in carSharingEntities.Users
                                   where userData.UserId == userId
                                   && userData.Activo
                                   select userData).FirstOrDefault();
                    if (usuario != null)
                    {
                        return !usuario.Prepago;
                    }
                }
            }
            catch (Exception)
            {
                return false;
            }
            return false;
        }

        public decimal ObtenerSaldoClienteActivo(int userId)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var usuario = (from userData in carSharingEntities.Users
                                   where userData.UserId == userId
                                   && userData.Activo
                                   select userData).ToList();
                    if (usuario.Count == 1)
                    {
                        foreach (var user in usuario)
                        {
                            return user.SaldoPrepago;
                        }
                    }
                }
            }
            catch (Exception)
            {
                return 0;
            }
            return 0;
        }

        public bool ClientePospago(int userId)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var usuario = (from userData in carSharingEntities.Users
                                   where userData.UserId == userId
                                   select userData).FirstOrDefault();
                    if (usuario != null)
                    {
                        return !usuario.Prepago;
                    }
                }
            }
            catch (Exception)
            {
                return false;
            }
            return false;
        }

        /// <summary>
        /// Modifica el viaje actual en kilometraje
        /// </summary>
        /// <param name="viajeId"></param>
        /// <param name="kilometros"></param>
        /// <returns></returns>
        public decimal ModificarViaje(int viajeId, decimal kilometros)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var precioKm = ObtenerPrecioPorKilometraje();
                    var costo = kilometros*precioKm;
                    var query = (from viaje in carSharingEntities.Trips
                                 where viaje.ViajeId == viajeId
                                 select viaje).ToList();
                    if (query.Count == 1)
                    {
                        foreach (var trip in query)
                        {
                            var saldoCliente = ObtenerSaldoCliente(trip.UserId);
                            if ((saldoCliente - costo > 0) || ClientePospago(trip.UserId))
                            {
                                trip.Kilometraje = kilometros;
                                trip.CostoViaje = kilometros * precioKm;
                                trip.Estado = (byte) TripStatus.Active;
                                carSharingEntities.SaveChanges();
                            }
                            return (saldoCliente - costo);
                        }
                        return -1;
                    }
                }
            }
            catch (Exception)
            {
                return -1;
            }
            return -1;
        }

        public decimal ModificarViaje(int userId, decimal kilometros, string estado)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var precioKm = ObtenerPrecioPorKilometraje();
                    var costo = kilometros * precioKm;
                    var query = (from viaje in carSharingEntities.Trips
                                 where viaje.UserId == userId && 
                                 viaje.Estado != (int) TripStatus.Ended
                                 select viaje).ToList();
                    if (query.Count == 1)
                    {
                        foreach (var trip in query)
                        {
                            var saldoCliente = ObtenerSaldoCliente(userId);
                            if ((saldoCliente - costo > 0) || ClientePospago(userId))
                            {
                                switch (estado)
                                {
                                    case "E":
                                        ModificarViaje(trip.ViajeId, kilometros);
                                        break;
                                    case "F":
                                        TerminarViaje(trip.ViajeId, kilometros);
                                        break;
                                }
                            }
                            else
                            {
                                TerminarViaje(trip.ViajeId, kilometros);
                            }
                            return (saldoCliente - costo) < 0 ? 0 : saldoCliente - costo;
                        }
                    }
                    return -2;
                }
            }
            catch (Exception)
            {
                return -2;
            }
        }

        public decimal ObtenerSaldoCliente(int userId)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var usuario = (from userData in carSharingEntities.Users
                                   where userData.UserId == userId
                                   select userData).ToList();
                    if (usuario.Count == 1)
                    {
                        foreach (var user in usuario)
                        {
                            return user.SaldoPrepago;
                        }
                    }
                }
            }
            catch (Exception)
            {
                return 0;
            }
            return 0;
        }

        /// <summary>
        /// Termina el viaje con el ultimo contador de kilometros
        /// </summary>
        /// <param name="viajeId"></param>
        /// <param name="kilometros"></param>
        /// <returns></returns>
        public int TerminarViaje(int viajeId, decimal kilometros)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var precioKm = ObtenerPrecioPorKilometraje();
                    var query = (from viaje in carSharingEntities.Trips
                                 where viaje.ViajeId == viajeId
                                 select viaje).ToList();
                    if (query.Count == 1)
                    {
                        foreach (var trip in query)
                        {
                            trip.Kilometraje = kilometros;
                            trip.CostoViaje = kilometros * precioKm;
                            trip.Estado = (byte) TripStatus.Ended;
                            carSharingEntities.SaveChanges();
                            if (DecrementarSaldoUsuario(trip.UserId, trip.CostoViaje))
                                return 1;
                        }
                    }
                }
            }
            catch (Exception)
            {
                return -1;
            }
            return -1;
        }

        private static bool DecrementarSaldoUsuario(int userId, decimal costoViaje)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var usuario = (from userData in carSharingEntities.Users
                                   where userData.UserId == userId
                                   select userData).ToList();
                    if (usuario.Count == 1)
                    {
                        foreach (var user in usuario)
                        {
                            user.SaldoPrepago = user.SaldoPrepago - costoViaje;
                            carSharingEntities.SaveChanges();
                            return true;
                        }
                    }
                }
            }
            catch (Exception)
            {
                return false;
            }
            return false;
        }

        public User ObtenerUsuario(int userId)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var usuario = (from userData in carSharingEntities.Users
                                   where userData.UserId == userId
                                   select userData).ToList();
                    if (usuario.Count == 1)
                    {
                        foreach (var user in usuario)
                        {
                            return user;
                        }
                    }
                }
            }
            catch (Exception)
            {
                return null;
            }
            return null;
        }

        /// <summary>
        /// Obtener los viajes finalizados por el cliente
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<Trip> ObtenerViajesUsuario(int userId)
        {
            List<Trip> viajes = new List<Trip>();
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var query = (from tripData in carSharingEntities.Trips
                                 where tripData.UserId == userId
                                   select tripData).ToList();
                    return query;
                }
            }
            catch (Exception ex)
            {
            }
            return viajes;
        }

        /// <summary>
        /// Obtener datos de un viaje especifico
        /// </summary>
        /// <param name="viajeId"></param>
        /// <returns></returns>
        public Trip ObtenerDetallesViaje(int viajeId)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var query = (from tripData in carSharingEntities.Trips
                                 where tripData.ViajeId == viajeId
                                 select tripData).FirstOrDefault();
                    return query;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public List<User> ObtenerUsuarios()
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var query = (from userData in carSharingEntities.Users
                                 select userData).ToList();
                    return query;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public bool ModificarUsuario(int userIdModified, string userName, string password, bool isActive, bool isPrepaid, decimal amount)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var queryExists = (from userData in carSharingEntities.Users
                                        where userData.UserId != userIdModified &&
                                        userData.UserName == userName
                                        select userData).ToList();
                    if (queryExists.Count > 0)
                    {
                        return false;
                    }
                    else
                    {
                        var query = (from userData in carSharingEntities.Users
                                     where userData.UserId == userIdModified
                                     select userData).FirstOrDefault();
                        query.UserName = userName;
                        query.UserPassword = password;
                        query.Activo = isActive;
                        query.Prepago = isPrepaid;
                        query.SaldoPrepago = amount;
                        carSharingEntities.SaveChanges();
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public bool EliminarUsuario(int userIdModified)
        {
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var queryExists = (from userData in carSharingEntities.Users
                                       where userData.UserId == userIdModified
                                       select userData).FirstOrDefault();
                    if (queryExists != null)
                    {
                        queryExists.Activo = false;
                        carSharingEntities.SaveChanges();
                        return true;
                    }
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public List<UsersTrips> ObtenerViajesUsuarios()
        {
            List<UsersTrips> usersTripses = new List<UsersTrips>();
            try
            {
                using (CarSharingEntities carSharingEntities = new CarSharingEntities())
                {
                    var queryExists = (from tripData in carSharingEntities.Trips
                                       join userData in carSharingEntities.Users on tripData.UserId equals userData.UserId
                                       select new
                                       {
                                           UserId = userData.UserId,
                                           UserName = userData.UserName,
                                           UserAmount = userData.SaldoPrepago,
                                           UserKm = tripData.Kilometraje,
                                           UserAmountSpend = tripData.CostoViaje
                                       }).ToList();

                    var query = (from data in queryExists
                                 group data by data.UserId into g
                                 select new UsersTrips()
                                 {
                                     UserId = g.First().UserId,
                                     UserName = g.First().UserName,
                                     UserAmount = g.First().UserAmount,
                                     UserKm = g.Sum(o => o.UserKm),
                                     UserAmountSpend = g.Sum(o => o.UserAmountSpend)
                                 }).ToList();

                    if (query.Count >0)
                    {
                        usersTripses = query;
                    }
                }
            }
            catch (Exception ex)
            {
            }
            return usersTripses;
        }
    }
}
